package com.rover12421.zkm.asm

import com.sun.org.apache.bcel.internal.generic.SIPUSH
import org.objectweb.asm.Opcodes
import org.objectweb.asm.tree.*

class ZkmMethodNode(api: Int, access: Int, name: String?, desc: String?,
                    signature: String?, exceptions: Array<out String>?)
    : MethodNode(api, access, name, desc, signature, exceptions) {

    constructor(access: Int, name: String?, desc: String?,
                signature: String?, exceptions: Array<out String>?) : this (
            Opcodes.ASM5, access, name, desc, signature, exceptions
    )

    /**
     *
    abc.a 为计算，可以替换掉
    LDC 13005864684910
    LDC 196028393910331
    INVOKESTATIC com/zelix/abc.a (JJ)Lcom/zelix/aba;
    LDC 73675667742532
    INVOKEINTERFACE com/zelix/aba.a (J)I
     */

    override fun visitInsn(opcode: Int) {
//        if (opcode == Opcodes.I2C) {
//            val last = instructions.last
//            if (last.opcode == Opcodes.LDC) {
//                val node = last as LdcInsnNode
//                println("i2c before is ldc : $node")
//            }
//        }
        if (opcode == Opcodes.IADD) {
            try {
                /**
                LDC -88996530
                SIPUSH -18097
                IADD

                ==>
                LDC

                 三条指令 转化成 一条指令完成
                 第一个简化完成！
                 */
                val arg2 = instructions.last
                val arg1 = arg2.previous
                var i1 = intNodeValue(arg1)
                var i2 = intNodeValue(arg2)
                instructions.remove(arg2)
                instructions.remove(arg1)
                val ldc = i1+i2
                instructions.add(LdcInsnNode(ldc))
                println("IADD($i1, $i2) to Ldc($ldc)")
                return
            } catch (_: RuntimeException) {
            }
        }

        super.visitInsn(opcode)
    }

    fun intNodeValue(node: AbstractInsnNode) : Int {
        if (node.opcode == Opcodes.LDC) {
            node as LdcInsnNode
            val cst = node.cst
            if (cst is Number) {
                return cst.toInt()
            }

        } else if (node.opcode == Opcodes.SIPUSH) {
            node as IntInsnNode
            return node.operand
        }

        throw RuntimeException("non int node")
    }
}

